//
// Created by hugan on 2021/9/13.
//

#include "SAPIManager.h"

SAPIManager::SAPIManager() = default;

SAPIManager::~SAPIManager() {
    release();
}

HRESULT SAPIManager::init(bool logDebug0) {
    logDebug = logDebug0;
    if (logDebug) std::cout << "SAPIManager.init" << std::endl;
    HRESULT hr = CoInitialize(nullptr);
    if (FAILED(hr)) return hr;
    hr = CoCreateInstance(CLSID_SpVoice, nullptr, CLSCTX_ALL, IID_ISpVoice, (void **) &pVoice);
    if (FAILED(hr)) {
        SAFE_RELEASE(pVoice)
        CoUninitialize();
    }
    return hr;
}

void SAPIManager::release() {
    /*
     * pVoice为空:
     *   .初始化失败
     *   .重复调用release
     * 都不需要CoUninitialize
     */
    if (!pVoice) return;
    if (logDebug) std::cout << "SAPIManager.release" << std::endl;
    stop();
    SAFE_RELEASE(pSpToken)
    SAFE_RELEASE(pVoice)
    CoUninitialize();
}

HRESULT SAPIManager::enumVoice(func_enumVoiceCallback callback) {
    IEnumSpObjectTokens *pSpEnumTokens = nullptr;
    HRESULT hr = SpEnumTokens(SPCAT_VOICES, nullptr, nullptr, &pSpEnumTokens);
    if (FAILED(hr)) return hr;

    ISpObjectToken *pSpTokenTemp = nullptr;
    while (SUCCEEDED(hr = pSpEnumTokens->Next(1, &pSpTokenTemp, nullptr)) && pSpTokenTemp != nullptr) {
        //引擎名称
        wchar_t *id = nullptr;
        pSpTokenTemp->GetId(&id);
        std::wstring name = std::wstring(id);

        callback(const_cast<wchar_t *>(name.substr(name.find_last_of('\\') + 1).c_str()));
//        结构体中的wchar传参失败
//        VoiceInfo voiceInfo;
//        voiceInfo.name = const_cast<wchar_t *>(name.substr(name.find_last_of('\\') + 1).c_str());
//        callback(voiceInfo);
        pSpTokenTemp->Release();
    }
    pSpEnumTokens->Release();
    return hr;
}

HRESULT SAPIManager::setVoice(int voiceIndex) {
    IEnumSpObjectTokens *pSpEnumTokens = nullptr;
    HRESULT hr = SpEnumTokens(SPCAT_VOICES, nullptr, nullptr, &pSpEnumTokens);
    if (FAILED(hr)) return hr;

    SAFE_RELEASE(pSpToken)
    hr = pSpEnumTokens->Item(voiceIndex, &pSpToken);
    if (FAILED(hr)) return hr;

    pSpEnumTokens->Release();
    stop();//设置前取消朗读,即使是未SetVoice也不会有异常
    return pVoice->SetVoice(pSpToken);
}

HRESULT SAPIManager::setVolume(int volume) {
    return pVoice->SetVolume(volume);
}

HRESULT SAPIManager::setRate(int rate) {
    return pVoice->SetRate(rate);
}

HRESULT SAPIManager::speak(LPCWSTR text) {
//    return pVoice->Speak(text, SPF_DEFAULT, nullptr);//阻塞当前线程
    return pVoice->Speak(text, SPF_ASYNC | SVSFPurgeBeforeSpeak, nullptr);
}

HRESULT SAPIManager::stop() {
    /*
     * SpeechVoiceSpeakFlags
     * https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms720892(v=vs.85)?redirectedfrom=MSDN
     */
    return pVoice->Speak(nullptr, SVSFPurgeBeforeSpeak, nullptr);
}

HRESULT SAPIManager::pause() {
    return pVoice->Pause();
}

HRESULT SAPIManager::resume() {
    return pVoice->Resume();
}



